package CelestialWorkflow;

import CelestialDataStructures.CreditCardType;
import CelestialDataStructures.*;
import java.util.regex.*;
import java.text.ParseException;
import java.util.Date;

public class Validation {

    public static final String EMAIL_PATTERN = "^[\\w._+-]+@([\\w-]+\\.)+[a-zA-Z]{2,4}$";
    public static final String NUMBERS_PATTERN = "^[0-9]+$";
    public static final String SYMBOLS_PATTERN = "[\\-()+\\s]";
    public static final String PHONE_PATTERN = "^(\\d{1,4})?(\\d{3})?(\\d{6}\\d+)$";
    public static final String PASSWORD_PATTERN = "^.{9,20}$";

    public static final Pattern patNumbers = Pattern.compile(NUMBERS_PATTERN);
    public static final Pattern patSymbols = Pattern.compile(SYMBOLS_PATTERN);

    public static boolean validateEmail(String email){
        return Pattern.matches(EMAIL_PATTERN, email);
    }
    /*************************************************************************/
    /* validate password */
    public static boolean validatePassword(String pw){

        return Pattern.matches(PASSWORD_PATTERN, pw);
    }
    /*************************************************************************/
    public static int getPasswordStrength(String pw){
        //-2 - too few characters
        //-1 - too many characters
        //0  - null
        //1  - weak
        //2  - moderate
        //3  - strong
        //4  - very strong

        if(pw.length() == 0) return 0;

        if(pw.length() < 9) return -2;

        if(pw.length() > 20) return -1;

        int iStrength = 0;

        if(Pattern.matches(".*[a-z]+.*", pw)) iStrength++;

        if(Pattern.matches(".*[A-Z]+.*", pw)) iStrength++;

        if(Pattern.matches(".*\\d+.*", pw)) iStrength++;

        if(Pattern.matches(".*[\\W]+.*",pw)) iStrength++;

        return iStrength;
    }
    /*************************************************************************/
    /* validate card number, also checks card issuer */
    public static boolean validateCreditCard(String cc, int type){

        /* check numbers first */
        if(!validateCreditCard(cc)) return false;

        /* check issuser */
        if(type==CreditCardType.AM_EXP)
            return Pattern.matches("^3[47][0-9]{13}$", removeSymbols(cc));

        if(type==CreditCardType.MASTER)
            return Pattern.matches("^5[1-5][0-9]{14}$", removeSymbols(cc));

        if(type==CreditCardType.VISA)
            return Pattern.matches("^4[0-9]{12}(?:[0-9]{3})?$", removeSymbols(cc));

        return false; // unrecognized type, so return false
    }
    /*************************************************************************/
    /* validate credit card using luhn algo */
    public static boolean validateCreditCard(String cc){

        /* get numbers only */
        cc = removeSymbols(cc);

        /* it should contains numbers only...*/
        if(!Pattern.matches(NUMBERS_PATTERN, cc)) return false;

        /* perform luhn check */
        boolean bOdd = true;
        int iSum = 0;
        int iDigit;
        for(int i = 0; i <= cc.length()-1 ; i++){

            iDigit = Integer.parseInt(cc.substring(i, i + 1));
            if(bOdd)
                iSum += (iDigit * 2) % 9;
            else
                iSum += iDigit;

            bOdd = !bOdd;
        }
        return (iSum % 10) == 0;
    }
    /*************************************************************************/
    public static boolean validatePhone(String phone){

        phone = removeSymbols(phone);

        /* it should contains only numbers... */
        if(!Pattern.matches(NUMBERS_PATTERN, phone)) return false;

        /* check for 1-4 country codes ?, 3 area codes ?, 7 digits */
        return Pattern.matches(PHONE_PATTERN, phone);
    }
    /*************************************************************************/
    public static Date validateDate(String year, String month, String day){

        return validateDate(year + "-" + month + "-" + day);
    }
    /*************************************************************************/
    public static Date validateDate(String date){
        try{
            return DateFormat.parse(date);
        }catch(ParseException ex){
            return null;
        }
    }
    /*************************************************************************/
    /* Helpers */
    private static String removeSymbols(String src){

        Matcher mat = patSymbols.matcher(src);

        return mat.replaceAll("");
    }
    /*************************************************************************/
    /* Test */
    public static void main(String[] args) throws Exception{

        System.out.println(validateDate("1984-11-31"));
        System.out.println(validatePassword("1#$   "));
        System.out.println(validatePhone("(+65)654622"));
        System.out.println(validateEmail("CHAN0503@e.edu.sg"));
        System.out.println(validateCreditCard("-55482740 3320 7951", CreditCardType.MASTER));

    }
}
